package cn.edu.zzuli.nothinglink.service.impl;

import cn.edu.zzuli.nothinglink.entity.Classes;
import cn.edu.zzuli.nothinglink.entity.R;
import cn.edu.zzuli.nothinglink.entity.Students;
import cn.edu.zzuli.nothinglink.entity.Teachers;
import cn.edu.zzuli.nothinglink.mapper.ClassesMapper;
import cn.edu.zzuli.nothinglink.mapper.StudentsMapper;
import cn.edu.zzuli.nothinglink.mapper.TeachersMapper;
import cn.edu.zzuli.nothinglink.service.ClassesService;
import cn.edu.zzuli.nothinglink.vo.ClassNewInfoVo;
import cn.edu.zzuli.nothinglink.vo.ClassVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author suzyyy
 * @since 2021-04-08
 */
@Service
public class ClassesServiceImpl extends ServiceImpl<ClassesMapper, Classes> implements ClassesService {

    @Resource
    TeachersMapper teachersMapper;

    @Resource
    StudentsMapper studentsMapper;

    @Resource
    ClassesMapper classesMapper;

    @Override
    public R createClass(Integer uId, JSONObject json) {
        //判断班级序号，来得知创建几个班级。
        List<String> classNumber = json.getJSONArray("classNumber").toJavaList(String.class);
        if (classNumber.size() == 1) {
            //生成班级信息
            Classes c = generateClassInfo(uId, json, classNumber.get(0));

            if (!save(c)) return R.error().add("error", "创建班级失败");

            //格式保持一致
            List<ClassNewInfoVo> urls = new ArrayList<>();
            urls.add(new ClassNewInfoVo().setClassName(c.getClassRealName())
                    .setClassUrl(c.getClassUrl()));

            return R.success().add("urls", urls);
        }

        CopyOnWriteArrayList<Classes> classes = new CopyOnWriteArrayList<>();

        //现在考虑批量创建班级的问题。
        classNumber.parallelStream().forEach(number -> classes.add(
                generateClassInfo(uId, json, number)
        ));

        //批量添加就完事了
        if (!saveBatch(classes)) return R.error().add("error", "创建班级失败");

        List<ClassNewInfoVo> urls = classes.stream().map(c ->
                    new ClassNewInfoVo().setClassName(c.getClassRealName()
                ).setClassUrl(c.getClassUrl())).collect(Collectors.toList());


        return R.success().add("urls", urls);
    }

    @Override
    public R listClassInfo(Integer uId, Integer type, Integer haveDeleted) {
        //type 为1,是全部查询，type为2,是查询当前用户所创建的
        //haveDeleted 为1 是全部查询，为2,代表去除已经关闭的班级，即搜索deleted为0的数据

        if (type == 1) {
            List<Classes> classes = judgeClassesWithDeleted(haveDeleted);
            getAllClassName(classes);
            return R.success().add("classInfos", classes);
        }

        List<Classes> classes = judgeClassesWithDeleted(haveDeleted);
        //过滤出 uId相等的情况
        List<Classes> myClasses = classes.stream()
                .filter(c -> c.getBelongTeaId() == uId)
                .collect(Collectors.toList());

        //如果是mysql5的话，这个还能用，毕竟有同一条mysql语句有缓存
        //但是我现在用的mysql8,这个版本已经去除缓存了，既然都是同一个创建的，那就搜索当前的老师信息就行了
        //getAllClassName(myClasses)
        Teachers t = teachersMapper.selectById(uId);
        myClasses.forEach(c -> c.setTeaName(t.getTeaName()));

        return R.success().add("classInfos", myClasses);
    }

    @Override
    public R getClassInfo(Integer classId) {
        Classes c = null;
        if ((c = getById(classId)) != null) {
            //我们要搜索的班级信息有学生信息，所以这里我们还是建个vo类来包装一下。
            ClassVo vo = new ClassVo();
            List<Students> stus = studentsMapper.selectList(
                    new LambdaQueryWrapper<Students>()
                            .select(Students::getStuId, Students::getStuName,
                                    Students::getStuNumber,
                                    Students::getStuPhone, Students::getStuEmail)
                            .eq(Students::getBelongClassId, c.getClassId())
            );
            vo.setClasses(c).setStuData(stus);
            return R.success().add("classInfo", vo);
        }
        else return R.success().add("classInfo", null);
    }

    @Override
    @Transactional
    public R bindClassByURL(String url, Integer stuId) {
        String[] split = url.split("/");
        url = split[split.length - 1];
        System.out.println(url);
        //根据url找到唯一的班级，然后修改学生的id
        Classes c = this.getOne(
                new LambdaQueryWrapper<Classes>().eq(
                        Classes::getClassUrl, url
                )
        );
        Students s = studentsMapper.selectById(stuId);
        if (s == null || c == null) return R.error().add("error", "没有对应的学生或者课程");

        if (s.getBelongClassId() == c.getClassId()) return R.error().add("error", "请不要绑定相同班级");
        //不一致的话，我们可以开始修改班级Id。
        //这里判断，如果更改班级了，那么还要更改原有班级的人数。
        if (s.getBelongClassId() == 0 || s.getBelongClassId() == null) {
            //初次绑定班级
            //修改班级人数, 即班级人数+1...
            synchronized (ClassesServiceImpl.class) {
                classesMapper.theClassNumberAddOne(c.getClassId());
            }
        }else {
            //更换班级了。原有班级人数-1, 新班级人数+1。
            synchronized (ClassesServiceImpl.class) {
                classesMapper.theClassNumberAddOne(c.getClassId());
                //原有班级人数 - 1
                classesMapper.theClassNumberReduceOne(s.getBelongClassId());
            }
        }

        studentsMapper.updateById(s.setBelongClassId(c.getClassId()));
        s.setClassName(c.getClassRealName());


        return R.success().add("stu", s);
    }

    private void getAllClassName(List<Classes> classes) {
        classes.parallelStream().forEach(c -> {

            Teachers t = teachersMapper.selectOne(
                    new LambdaQueryWrapper<Teachers>().select(
                            Teachers::getTeaName
                    ).eq(Teachers::getTeaId, c.getBelongTeaId())
            );
            c.setTeaName(t.getTeaName());
        });
    }

    private List<Classes> judgeClassesWithDeleted(Integer haveDeleted) {
        List<Classes> classes = null;
        if (haveDeleted == 2) {
            classes = list().stream()
                    .filter(c -> c.getDeleted() == 0)
                    .collect(Collectors.toList());
        }else {
            classes = list();
        }

        return classes;
    }


    private Classes generateClassInfo(Integer uId, JSONObject json, String number) {
        //生成班级URL，uuid重复几率很小。
        String classUrl = UUID.randomUUID().toString().replaceAll("-", "");

        //设置基本信息
        Classes c = new Classes();
        c.setClassCollege(json.getString("college"))
                .setBelongTeaId(uId)
                .setClassNumber(number)
                .setClassUrl(classUrl)
                .setClassName(json.getString("className"))
                .setClassSession(json.getInteger("classSession").toString())
                .setClassLimitNumber(json.getInteger("stuNumber"));
        //生成 real-name
        c.setClassRealName(
                c.getClassName()+c.getClassSession()+c.getClassNumber()
        );

        return c;
    }
}
